SOFTWARE II

Análisis de datos en R para Ciencia de Datos

Grado en Ciencia de Datos Aplicada • Javier Álvarez Liébana

¡Bienvenidos a R!

Dejad vuestras hojas de cálculo y Anacondas a un lado

¡Buenas!

Correo: . Despacho: 722 (3ª planta). Tutorías: …

  • Javier Álvarez Liébana, de Carabanchel (Bajo).

  • Licenciado en Matemáticas (UCM). Doctorado en estadística (UGR).

  • Encargado de la visualización y análisis de datos covid del Principado de Asturias (2021-2022).

  • Miembro de la Sociedad Española de Estadística e IO y la Real Sociedad Matemática Española.

Actualmente, investigador y docente en la Facultad de Estadística de la UCM. Divulgando por Twitter e Instagram

Objetivos

  • Quitarnos el miedo a los errores en programación → a programar se aprende programando

  • Entender los conceptos básicos de R desde cero → aprender a abstraer ideas y algoritmos

  • Utilidad de programar → flujos de trabajo reproducibles, transparentes y mantenibles

  • Introducción al análisis y preprocesamiento de datos → {tidyverse}

  • Adquirir habilidades en la visualización de datos{ggplot2}

Evaluación

  • Asistencia. No será obligatoria pero se valorará positivamente la participación.
  • Evaluación continua. A lo largo del curso se han planteado 3 entregas individuales (15%-25%-35%), así como una entrega final grupal (25%) (entre 4 y 6 personas). La nota solo ponderará si supera el 3.5 de media.
  • Examen final: si el final tiene peso deberás sacar al menos un 3 para que pondere.

    • Entre 3.5 y 5 –> podrás decidir peso del final entre el 80% y el 100%
    • Entre 5 y 6 –> entre el 60% y el 100%.
    • Entre 6 y 7 –> entre el 40% y el 100%.
    • Entre 7 y 8 –> entre el 20% y el 100%.
    • Más de un 8 –> entre el 0% y el 100% (podrás no presentarte al final).

Planificación entregas

  • Entrega I (15%): semana …

  • Entrega II (25%):

  • Entrega III (35%):

 

  • Entrega grupal (25%): último día de clase

 

Se podrán modificar las fechas por saturación con otras asignaturas siempre y cuando el/la delegado/a lo solicite con más de 10 días de antelación.

Planificación

CLASE SEMANA FECHAS TOPIC EJ. WORKBOOK ENTREGA
1 S1 12 sep Primeros pasos en R 💻
2 S1 15 sep Tipos básicos de datos y vectores 💻 💻 🐣
3 S2 15 sep Primeras bases de datos 💻 💻 💻 🐣

Materiales

En el menú de las diapositivas (abajo a la izquierda) tienes una opción para descargarlas en pdf en Tools

 

 

Clase 1: primeros pasos

Instalando R y RStudio. Primeros pasos. Scripts y proyectos

Requisitos

Para el curso los únicos requisitos serán:

  1. Conexión a internet (para la descarga de algunos datos y paquetes).
  1. Instalar R: será nuestro lenguaje. La descarga la haremos (gratuitamente) desde https://cran.r-project.org/

R vs RStudio

Programaremos como escribimos (castellano, por ejemplo) → R es lenguaje

  • Necesitaremos una gramática, un lenguaje (R)
  • Y un entorno, por ejemplo un Word (RStudio), para escribirlo

Instalación de R

El lenguaje R será nuestra gramática y ortografía (nuestras reglas de juego)

  • Paso 1: entra en https://cran.r-project.org/ y selecciona tu sistema operativo.

  • Paso 2: para Mac basta con que hacer click en el archivo .pkg, y abrirlo una vez descargado. Para sistemas Windows, debemos clickar en install R for the first time y después en Download R for Windows. Una vez descargado, abrirlo como cualquier archivo de instalación.

  • Paso 3: abrir el ejecutable de instalación.

Cuidado

Siempre que tengas que descargar algo de CRAN (ya sea el propio R o un paquete), asegúrate de tener conexión a internet.

Primera operación

Para comprobar que se ha instalado correctamente, tras abrir R, deberías ver el R GUI(Graphical User Interface), y en él, una pantalla blanca similar a esta: se llama consola y podemos hacer un primer uso de ella como una calculadora.

Primer código: a una variable llamada a le asignaremos el valor 1 (escribiremos el código de abajo en la consola y daremos «enter»)

a <- 1

Primera operación

Para comprobar que se ha instalado correctamente, tras abrir R, deberías ver una pantalla blanca similar a esta: se llama consola y podemos hacer un primer uso de ella como una calculadora.

Primer código: definiremos otra variable llamada b y le asignaremos el valor 2

a <- 1
b <- 2

Fíjate que…

En R asignaremos valores con <- como una flecha: la variable a la izquierda de dicha flecha le asignamos el valor que hay a la derecha (por ejemplo, a <- 1)

Primera operación

Para comprobar que se ha instalado correctamente, tras abrir R, deberías ver una pantalla blanca similar a esta: se llama consola y podemos hacer un primer uso de ella como una calculadora.

Primer código: haremos la suma a + b y nos devolverá su resultado

a <- 1
b <- 2
a + b
[1] 3

Fíjate que…

En la consola aparece un número [1]: simplemente es un contador de elementos (como contar filas en un Word)

Instalación de R Studio

RStudio será el Word que usaremos para escribir (lo que se conoce como un IDE: entorno integrado de desarrollo).

  • Paso 1: entra la web oficial de RStudio (ahora llamado Posit) y selecciona la descarga gratuita.

  • Paso 2: selecciona el ejecutable que te aparezca acorde a tu sistema operativo.

  • Paso 3: tras descargar el ejecutable, hay que abrirlo como otro cualquier otro y dejar que termine la instalación.

Organización de RStudio

Al abrir RStudio seguramente tengas tres ventanas:

  • Consola: es el nombre para llamar a la ventana grande que te ocupa buena parte de tu pantalla. Prueba a escribir el mismo código que antes (la suma de las variables) en ella. La consola será donde ejecutaremos órdenes y mostraremos resultados.

Organización de RStudio

Al abrir RStudio seguramente tengas tres ventanas:

  • Environment: la pantalla pequeña (puedes ajustar los márgenes con el ratón a tu gusto) que tenemos en la parte superior derecha. Nos mostrará las variables que tenemos definidas.

Organización de RStudio

Al abrir RStudio seguramente tengas tres ventanas:

  • Panel multiusos: la ventana que tenemos en la parte inferior derecha no servirá para buscar ayuda de funciones, además de para visualizar gráficos.

¿Qué es R? ¿Por qué R?

¿Qué es R? ¿Por qué R?

R es la evolución del trabajo de los laboratorios Bell con el lenguaje S, que fue llevado al mundo del software libre por Ross Ihaka y Robert Gentleman en los años 90. La version R 1.0.0 se publicó el 29 de febrero de 2000.

¿Qué es R? ¿Por qué R?

R es el lenguaje estadístico por excelencia, creado por y para estadísticos/as, con 6 ventajas fundamentales frente a Excel, SAS, Stata o SPSS:

  • Lenguaje de programación: la obviedad → análisis replicables
  • Gratuito: la filosofía de la comunidad de R es el compartir código bajo copyleftuso ético de dinero y algoritmos
  • Software libre: no solo es gratis sino que permite acceder libremente a código ajeno, incluso al propio código fuenteflexibilidad y transparencia (Free and Open Source Software FOSS)

¿Qué es R? ¿Por qué R?

R es el lenguaje estadístico por excelencia, creado por y para estadísticos/as, con 6 ventajas fundamentales frente a Excel, SAS, Stata o SPSS:

  • Lenguaje modular: hemos instalado lo mínimo, pero existen códigos de otras personas que podemos reusar (casi 20 000 paquetes) → ahorro de tiempo e innovación inmediata
  • Lenguaje de alto nivel: facilita la programación (como Python) → menor curva de aprendizaje
  • Comunidad y empleabilidad: junto con Python es el lenguaje más utilizado en el campo de la estadística y la ciencia de datos en investigación, docencia, empresas (Línea Directa, Mapfre, Telefónica, Orange, Apple, Spotify, Netflix, El País, Civio, HP, etc) y organismos públicos (ISCIII, CNIC, CNIO, INE, IGN, CIS, CEO, DGT, AEMET, RTVE, etc)

¿Por qué programar?

  • Automatizar → te permitirá automatizar tareas recurrentes.

  • Replicabilidad → podrás replicar tu análisis siempre de la misma manera.

  • Flexibilidad → podrás adaptar el software a tus necesidades.

  • Transparencia → ser auditado por la comunidad.

Idea fundamental: paquetes

Una de las ideas claves de R es el uso de paquetes: códigos que otras personas han implementado para resolver un problema

  • Instalación: descargamos los códigos de la web (necesitamos internet) → comprar un libro, solo una vez (por ordenador)
install.packages("ggplot2")
  • Carga: con el paquete descargado, indicamos qué paquetes queremos usar cada vez que abramos RStudiotraer el libro de la estantería
library(ggplot2)

Idea fundamental: paquetes

Una vez instalado, hay dos manera de usar un paquete (traerlo de la estantería)

  • Paquete entero: con library(), usando el nombre del paquete sin comillas, cargamos en la sesión todo el libro
library(ggplot2)
  • Funciones concretas usando paquete::funcion le índicamos que solo queremos una página concreta de ese libro
ggplot2::geom_point()

Te vas equivocar

Durante tu aprendizaje va a ser muy habitual que las cosas no salgan a la primera → te vas equivocar. No solo será importante asumirlo sino que es importante leer los mensajes de error para aprender de ellos.

  • Mensajes de error: precedidos de «Error in…» y serán aquellos fallos que impidan la ejecución
"a" + 1 
Error in "a" + 1: argumento no-numérico para operador binario
  • Mensajes de warning: precedidos de «Warning in…» son los (posibles) fallos más delicados ya que son incoherencias que no impiden la ejecución
# Ejecuta la orden pero el resultado es NaN, **Not A Number**, un valor que no existe
sqrt(-1)
Warning in sqrt(-1): Se han producido NaNs
[1] NaN

Scripts (documentos .R)

Un script será el documento en el que programamos, nuestro archivo .doc (aquí con extensión .R) donde escribiremos las órdenes. Para abrir nuestro primero script, haz click en el menú en File < New File < R Script.

Cuidado

Es importante no abusar de la consola: todo lo que no escribas en un script, cuando cierres, lo habrás perdido.

Cuidado

R es case-sensitive: es sensible a mayúsculas y minúsculas por lo que x y X representa variables distintas.

Ejecutando el primer script

Ahora tenemos una cuarta ventana: la ventana donde escribiremos nuestros códigos. ¿Cómo ejecutarlo?

  1. Escribimos el código a ejecutar.
  1. Guardamos el archivo .R haciendo click en Save current document.
  1. El código no se ejecuta salvo que se lo indiquemos. Tenemos tres opciones de ejecutar un script:
  • Copiar y pegar en consola.
  • Seleccionar líneas y Ctrl+Enter
  • Activar Source on save a la derecha de guardar: no solo guarda sino que ejecuta el código completo.

Sé organizado: proyectos

De la misma manera que en el ordenador solemos trabajar de manera ordenada por carpetas, en RStudio podemos hacer lo mismo para trabajar de manera eficaz creando proyectos.

Un proyecto será una «carpeta» dentro de RStudio, de manera que nuestro directorio raíz automáticamente será la propia carpeta de proyecto (pudiendo pasar de un proyecto a otro con el menu superior derecho).

Podemos crear uno en una carpeta nueva o en una carpeta ya existente.

💻 Tu turno

📝 Crea en tu ordenador una carpeta de la asignatura y crea dentro de ella el proyecto de RStudio: es ahí donde vas a guardar todo lo que hagamos a lo largo de este curso.Tras crear el proyecto tendrás un archivo R Project. A continuación crea en dicha carpeta dos subcarpetas: datos (es ahí donde irás guardando los distintos datasets que usaremos) y scripts (es ahí donde irás guardando los archivos .R de cada clase)

📝 Dentro del proyecto crea un script ejercicios-clase1.R (dentro de la carpeta scripts). Una vez creado define en él una variable de nombre a y cuyo valor sea -1. Ejecuta el código de las 3 maneras explicadas.

Código
a <- -1

📝 Añade debajo otra línea para definir una variable b con el valor 5. Tras ello guarda la multiplicación de ambas variables. Ejecuta el código como consideres.

Código
b <- 5
a * b # sin guardar
multiplicacion <- a * b # guardado

📝 Modifica el código inferior para definir dos variables c y d, con valores 3 y -1. Tras ello divide las variables y guarda el resultado.

c <- # deberías asignarle el valor 3
d <- # deberías asignarle el valor -1
Código
c <- 3
d <- -1
c / d # sin guardar
division <- c / d # guardado

📝 Asigna un valor positivo a x y calcula su raíz cuadrada; asigna otro negativo y y calcula su valor absoluto con la función abs().

Código
x <- 5
sqrt(x)

y <- -2
abs(y)

Toma nota

Comandos como sqrt(), abs() o max() son lo que llamamos funciones: líneas de código que hemos «encapsulado» bajo un nombre, y dado unos argumentos de entrada, ejecuta las órdenes (una especie de atajo). En las funciones los argumentos irán SIEMPRE entre paréntesis

📝 Usando la variable x ya definida, completa/modifica el código inferior para guardar en una nueva variable z el resultado guardado en x menos 5.

z <- ? - ? # completa el código
z
Código
z <- x - 5
z

📝 Define una variable x y asígnale el valor -1. Define otra y y asígnale el valor 0. Tras ello realiza las operaciones a) x entre y; b) raíz cuadrada de x. ¿Qué obtienes?

Código
x <- -1
y <- 0

x / y
sqrt(x)

📝 Escribe el código inferior en tu script. ¿Por qué crees que no funciona?

x <- -1
y <- 0

X + y

Clase 2: primeros datos y vectores

¿Qué tipos de celdas (datos) existen? Concatenando celdas: vectores

De la CELDA a la TABLA

¿Qué tipo de dato podemos tener en cada celda de una tabla?

  • Celda: dato individual de un tipo concreto.
  • Variable: concatenación de valores del mismo tipo (vectores en R).
  • Matriz: concatenación de variables del mismo tipo y longitud.
  • Tabla: concatenación de variables de distinto tipo pero igual longitud
  • Lista: concatenación de variables de distinto tipo y distinta longitud

Pero antes…buenas prácticas

Antes de seguir, es importante que sepas algo cuánto antes: empezar en la programación puede ser frustrante

Al igual que cuando aprendes un idioma nuevo, el primer obstáculo a solventar no es tanto qué decir sino cómo decirlo de manera correcta. Y en R pasa lo mismo, así que vamos a normalizar nuestra forma de programar lo máximo posible para evitar errores futuros.

  • Tip 1: asignar, evaluar y comparar no es lo mismo. Si te has fijado en R estamos usando <- para asignar valores a variables. Usaremos = para evaluar argumentos en funciones y == para saber si dos elementos son iguales.
x <- 1 # asignar
x = 1 # evaluar
x == 1 # comparar

Pero antes…buenas prácticas

  • Tip 2: programa como escribes. Al igual que cuando redactas en castellano, acostúmbrate a incorporar espacios y saltos de línea paranoquedarteciego (es una buena práctica y no un requisito porque R no procesa los espacios)
x <- 1 # óptimo
x<-1 # regu
x<- 1 # peor (decídete)
  • Tip 3: no seas caótico/a, estandariza nombres. Acostúmbrate siempre a nombrar las variables de la misma manera. El único requisito es que debe empezar siempre por una letra (y sin tildes). La forma más recomendable es la conocida como snake_case
variable_en_modo_snake_case
otraFormaMasDificilDeLeer
hay.gente.que.usa.esto
Incluso_Haygente.Caotica_que.NoMereceNuestraATENCION

Pero antes…buenas prácticas

  • Tip 4: facilita la lectura y escritura, pon límites. En Tools < Global Options puedes personalizar algunas opciones de RStudio. En Code < Display podemos indicarle en Show margin que los scripts nos muestren un margen “imaginario” (no interacciona con el código) para “forzarnos” a realizar un salto de línea.

Pero antes…buenas prácticas

  • Tip 5: el tabulador es tu mejor amigo. En RStudio tenemos una herramienta maravillosa: si escribes parte del nombre de una variable o función y tabulas, RStudio te autocompleta

Pero antes…buenas prácticas

  • Tip 6: ni un paréntesis soltero. Siempre que abras un paréntesis deberás cerrarlo. Para facilitar esta tarea entra en Tools < Global Options < Code < Display y activa la opción Rainbow parentheses

Pero antes…buenas prácticas

  • Tip 7: fíjate en el lateral izquierdo. No solo podrás ver la línea de código por la que vas sino que, en caso de estar cometiendo un error de sintaxis, el propio RStudio te avisará.

Celdas: tipos de datos

¿Existen variables más allá de los números en la ciencia de datos? Piensa por ejemplo en los datos que podrías guardar de una persona:

  • La edad o el peso será un número.
edad <- 33
  • Su nombre será una cadena de texto (conocida como string o char).
nombre <- "javi"
  • A la pregunta «¿estás matriculado en la Facultad?» la respuesta será lo que llamamos una variable lógica (TRUE si está matriculado o FALSE en otro caso).
matriculado <- TRUE
  • Su fecha de nacimiento será precisamente eso, una fecha.

Variables numéricas

El dato más sencillo (ya lo hemos usado) serán las variables numéricas

a <- 5
a

Para saber la clase de dato en R de una variable tenemos la función class()

class(a)
[1] "numeric"

Para saber su tipología (naturaleza o formato) variable tenemos typeof()

typeof(1) # 1 pero almacenado como un valor real (double, con decimales)
[1] "double"
typeof(as.integer(1)) # 1 pero almacenado como un entero.
[1] "integer"

Fíjate que…

En R tenemos una colección de funciones que empiezan por as.x() y que sirven como funciones de conversión: un dato que era de un tipo, lo convertimos a tipo x.

Variables numéricas

Además de los números «normales» tendremos el valor más/menos infinito codificado como Inf o -Inf

1/0
[1] Inf
-1/0
[1] -Inf

Y valores que no son números reales not a number (indeterminaciones, complejos, etc) codificado como NaN

0/0
[1] NaN
sqrt(-2)
[1] NaN

Variables numéricas

Con las variables numéricas podemos realizar las operaciones aritméticas de una calculadora: sumar (+)…

a + b
[1] 7

…raíz cuadrada (sqrt())…

sqrt(a)
[1] 2.236068

… potencias (^2, ^3)…

a^2
[1] 25

…valor absoluto (abs()), etc.

abs(a)
[1] 5

Variables de texto

Imagina que además de la edad de una persona queremos guardar su nombre: ahora la variable será de tipo character

nombre <- "Javier"
class(nombre)
[1] "character"

Las cadenas de texto son un tipo con el que obviamente no podremos hacer operaciones aritméticas (sí otras operaciones como pegar o localizar patrones).

nombre + 1 # error al sumar número a texto
Error in nombre + 1: argumento no-numérico para operador binario

Recuerda que…

Las variables de tipo texto (character o string) van SIEMPRE entre comillas: no es lo mismo TRUE (valor lógico, binario) que "TRUE" (texto).

Primera función: paste

Como hemos comentado R llamaremos función a un trozo de código encapsulado bajo un nombre, y que depende de unos argumentos de entrada. Nuestra primera función será paste(): dadas dos cadenas de texto nos permite pegarlas.

paste("Javier", "Álvarez")
[1] "Javier Álvarez"

Fíjate que por defecto nos pega las cadenas con un espacio, pero podemos añadir un argumento opcional para indicarle el separador (en sep = ...).

paste("Javier", "Álvarez", sep = "*")
[1] "Javier*Álvarez"

Primera función: paste

¿Cómo saber qué argumentos necesita una función? Escribiendo en consola ? paste te aparecerá una ayuda en el panel multiusos.

En dicha ayuda podrás ver en su cabecera que argumentos ya tiene asignados por defecto la función

Existe una función similar llamada paste0() que pega por defecto con sep = "" (sin nada).

paste0("Javier", "Álvarez")
[1] "JavierÁlvarez"

Primera función: paste

Los argumentos (y su detalle) también pueden ser consultado tabulando (detras una coma).

Funciones: argumentos por defecto

Es muy importante entender el concepto de argumento por defecto de una función en R: es un valor que la función usa pero a veces podemos no ver porque ya tiene un valor asignado.

# Hacen lo mismo
paste("Javier", "Álvarez")
[1] "Javier Álvarez"
paste("Javier", "Álvarez", sep = " ")
[1] "Javier Álvarez"

Toma nota

El operador = lo reservaremos para asignar argumentos dentro de funciones. Para todas las demás asignaciones usaremos <-

Primer paquete: glue

Una forma más intuitiva de trabajar con textos es usar el paquete {glue}: lo primero que haremos será «comprar el libro» (si nunca lo hemos hecho). Tras ello cargamos el paquete

install.packages("glue") # solo la primra vez
library(glue)

Con la función glue() de dicho paquete podemos usar variables dentro de cadenas de texto. Por ejemplo, «la edad es de … años», donde la edad está guardada en una variable.

edad <- 33
glue("La edad es de {edad} años")
La edad es de 33 años

Dentro de las llaves también podemos ejecutar operaciones

unidades <- "días"
glue("La edad es de {edad * 365} {unidades}")
La edad es de 12045 días

Variables lógicas

Otro tipo fundamental serán las variables lógicas o binarias (dos valores):

  • TRUE: verdadero guardado internamente como un 1.
  • FALSE: falso guardado internamente como un 0.
soltero <- TRUE # ¿Es soltero? --> SÍ
class(soltero)
[1] "logical"

Dado que internamente están guardados como variables binarias, podemos realizar operaciones aritméticas con ellas

2 * TRUE
[1] 2
FALSE - 1
[1] -1

Variables lógicas

Como veremos en breve, las variables lógicas en realidad puede tomar un tercer valor: NA o dato ausente, representando las siglas de not available, y será muy habitual encontrarlo dentro de una base de datos.

ausente <- NA
ausente + 1
[1] NA

Importante

Las variables lógicas NO son variables de texto: "TRUE" es un texto, TRUE es un valor lógico.

TRUE + 1
[1] 2
"TRUE" + 1
Error in "TRUE" + 1: argumento no-numérico para operador binario

Condiciones lógicas

Los valores lógicos suelen ser resultado de evaluar condiciones lógicas. Por ejemplo, imaginemos que queremos comprobar si una persona se llama Javi.

nombre <- "María"

Con el operador lógico == preguntamos sí lo que tenemos guardado a la izquierda es igual que lo que tenemos a la derecha: es una pregunta

nombre == "Javi"
[1] FALSE

Con su opuesto != preguntamos si es distinto.

nombre != "Javi"
[1] TRUE

Fíjate que…

No es lo mismo <- (asignación) que == (estamos preguntando, es una comparación lógica).

Condiciones lógicas

Además de las comparaciones «igual a» frente «distinto», también comparaciones de orden como menor que <, mayor que >, <= o >=.

¿Tiene la persona menos de 32 años?

edad <- 34
edad < 32 # ¿Es la edad menor de 32 años?
[1] FALSE

¿La edad es mayor o igual que 38 años?

edad >= 38
[1] FALSE

¿El nombre guardado es Javi?

nombre <- "Javi"
nombre == "Javi"
[1] TRUE

Variables de fecha

Un tipo de datos muy especial: los datos de tipo fecha.

fecha_char <- "2021-04-21"

Parece una simple cadena de texto pero debería representar un instante en el tiempo. ¿Qué debería suceder si sumamos un 1 a una fecha?

fecha_char + 1
Error in fecha_char + 1: argumento no-numérico para operador binario

Las fechas NO pueden ser texto: debemos convertir la cadena de texto a fecha.

 

Para trabajar con fechas usaremos el paquete {lubridate}, que deberemos instalar antes de poder usarlo.

install.packages("lubridate")

Variables de fecha

Una vez instalado, de todos los paquetes (libros) que tenemos, le indicaremos que nos cargue ese concretamente.

library(lubridate) # instala si no lo has hecho

Para convertir a tipo fecha usaremos la función as_date() del paquete {lubridate} (por defecto en formato yyyy-mm-dd)

 

# ¡no es una fecha, es un texto!
fecha_char + 1
Error in fecha_char + 1: argumento no-numérico para operador binario
class(fecha_char)
[1] "character"
fecha <- as_date("2023-03-28")
fecha + 1
[1] "2023-03-29"
class(fecha)
[1] "Date"

Variables de fecha

En as_date() el formato de fecha por defecto es yyyy-mm-dd así si la cadena de texto no se introduce de manera adecuada…

as_date("28-03-2023")
[1] NA

Para cualquier otro formato debemos especificarlo en el argumento opcional format = ... tal que %d representa días, %m meses, %Y en formato de 4 años y %y en formato de 2 años.

as_date("28-03-2023", format = "%d-%m-%Y")
[1] "2023-03-28"
as_date("28-03-23", format = "%d-%m-%y")
[1] "2023-03-28"
as_date("03-28-2023", format = "%m-%d-%Y")
[1] "2023-03-28"
as_date("28/03/2023", format = "%d/%m/%Y")
[1] "2023-03-28"

Variables de fecha

En dicho paquete tenemos funciones muy útiles para manejar fechas:

  • Con today() podemos obtener directamente la fecha actual.
today()
[1] "2024-05-16"
  • Con now() podemos obtener la fecha y hora actual
now()
[1] "2024-05-16 11:35:06 CEST"
  • Con year(), month() o day() podemos extraer el año, mes y día
fecha <- today()
year(fecha)
[1] 2024
month(fecha)
[1] 5

Resúmenes de paquetes

Amplia contenido

Tienes un resumen en pdf de los paquetes más importantes en la carpeta correspondiente en el campus

💻 Tu turno

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Define una variable que guarde tu edad (llamada edad) y otra con tu nombre (llamada nombre)

Código
edad <- 33
nombre <- "Javi"

📝 Comprueba con dicha variable edad si NO tiene 60 años o si se llama "Ornitorrinco" (debes obtener variables lógicas como resultado)

Código
edad != 60 # distinto de
nombre == "Ornitorrinco" # igual a

📝 ¿Por qué el código inferior da error?

edad + nombre
Error in edad + nombre: argumento no-numérico para operador binario

📝 Define otra variable llamada hermanos que responda la pregunta «¿tienes hermanos?» y otra variable que almacene tu fecha de nacimiento (llamada fecha_nacimiento).

Código
hermanos <- TRUE

library(lubridate) # sino lo tenías ya cargado
fecha_nacimiento <- as_date("1989-09-10")

📝 Define otra variable con tus apellidos (llamada apellidos) y usa glue() para tener, en una sola variable llamada nombre_completo, tu nombre y apellidos separando nombre y apellido por una coma

Código
apellidos <- "Álvarez Liébana"
glue("{nombre}, {apellidos}")

📝 De fecha_nacimiento extrae el mes.

Código
month(fecha_nacimiento)

📝 Calcula los días que han pasado desde la fecha de tu nacimiento hasta hoy (con la fecha de nacimiento definida en el ejercicio 4).

Código
today() - fecha_nacimiento

Vectores: concatenar

Cuando trabajamos con datos normalmente tendremos columnas que representan variables: llamaremos vectores a una concatenación de celdas (valores) del mismo tipo (lo que sería una columna de una tabla).

La forma más sencilla es con el comando c() (c de concatenar), y basta con introducir sus elementos entre paréntesis y separados por comas

edades <- c(32, 27, 60, 61)
edades
[1] 32 27 60 61

Consejo

Un número individual x <- 1 (o bien x <- c(1)) es en realidad un vector de longitud uno –> todo lo que sepamos hacer con un número podemos hacerlo con un vector de ellos.

Vectores: concatenar

Como ves ahora en el environment tenemos una colección de elementos guardada

edades
[1] 32 27 60 61

La longitud de un vector se puede calcular con length()

length(edades)
[1] 4

También podemos concatenar vectores entre sí (los repite uno tras otro)

c(edades, edades, 8)
[1] 32 27 60 61 32 27 60 61  8

Secuencias numéricas

El vector más famoso será el de tipo numérico, y en concreto, las conocidas como secuencias numéricas (por ejemplo, los días del mes), usadas para, entre otras cosas, indexar bucles.

El comando seq(inicio, fin) nos permite crear una secuencia numérica desde un elemento inicial hasta uno final, avanzando de uno en uno.

seq(1, 31)
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26 27 28 29 30 31

Fíjate que si hacemos eso con caracteres no podremos hacerlo ya que no hay un orden a priori entre textos.

"a":"z"
Error in "a":"z": Argumento NA/NaN

Secuencias numéricas

Un atajo es el comando 1:n, que nos devuelve lo mismo que seq(1, n)

1:7
[1] 1 2 3 4 5 6 7

Si el elemento inicial es mayor que el final, entenderá que la secuencia es en orden decreciente.

7:-3
 [1]  7  6  5  4  3  2  1  0 -1 -2 -3

También podemos definir otro tipo de distancia (paso) entre consecutivos con el argumento by = ...

seq(1, 7, by = 0.5) # secuencia desde 1 a 7 de 0.5 en 0.5
 [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0

Secuencias numéricas

Otras veces nos interesará definir una secuencia con una longitud concreta

seq(1, 50, l = 7) # secuencia desde 1 a 50 de longitud 7
[1]  1.000000  9.166667 17.333333 25.500000 33.666667 41.833333 50.000000

Incluso puede nos interese generar un vector de n elementos repetidos

rep(0, 7) # vector de 7 ceros
[1] 0 0 0 0 0 0 0

Dado que internamente son guardados como números también podremos hacer esto con fechas.

seq(as_date("2023-09-01"), as_date("2023-09-10"), by = 1)
 [1] "2023-09-01" "2023-09-02" "2023-09-03" "2023-09-04" "2023-09-05"
 [6] "2023-09-06" "2023-09-07" "2023-09-08" "2023-09-09" "2023-09-10"

Vectores de caracteres

Un vector es una concatenación de elementos del mismo tipo, pero no tienen porque ser necesariamente números. Vamos a crear una frase de ejemplo.

frase <- "Me llamo Javi"
frase
[1] "Me llamo Javi"
length(frase)
[1] 1

En el caso anterior no era un vector, era un solo elemento de texto. Para crear un vector debemos usar de nuevo c() y separar elementos entre comas

vector <- c("Me", "llamo", "Javi")
vector
[1] "Me"    "llamo" "Javi" 
length(vector)
[1] 3

Vectores de caracteres

¿Qué sucederá si concatenamos elementos de diferente tipo?

c(1, 2, "javi", "3", TRUE)
[1] "1"    "2"    "javi" "3"    "TRUE"

Fíjate que como todos tienen que ser del mismo tipo, lo que hace R es convertir todo a texto, violando la integridad del dato

c(3, 4, TRUE, FALSE)
[1] 3 4 1 0

Es importante entender que los valores lógicos en realidad están almacenados internamente como 0/1

Operaciones con vectores

Con los vectores numéricos podemos hacer las mismas operaciones aritméticas que con los números → un número es un vector (de longitud uno)

¿Qué sucederá si sumamos o restamos un valor a un vector?

x <- c(1, 3, 5, 7)
x + 1
[1] 2 4 6 8
x * 2
[1]  2  6 10 14

Cuidado

Salvo que indiquemos lo contrario, en R las operaciones con vectores son siempre elemento a elemento

Suma de vectores

Los vectores también pueden interactuar entre ellos, así que podemos definir, por ejemplo, sumas de vectores (elemento a elemento)

x <- c(2, 4, 6)
y <- c(1, 3, 5)
x + y
[1]  3  7 11

Dado que la operación (por ejemplo, una suma) se realiza elemento a elemento, ¿qué sucederá si sumamos dos vectores de distinta longitud?

z <- c(1, 3, 5, 7)
x + z
[1]  3  7 11  9

Lo que hace es reciclar elementos: si tiene un vector de 4 elementos y sumamos otro de 3 elementos, lo que hará será reciclar del vector con menor longitud.

Comparar vectores

Una operación muy habitual es preguntar a los datos mediante el uso de condiciones lógicas. Por ejemplo, si definimos un vector de temperaturas…

¿Qué días hizo menos de 22 grados?

x <- c(15, 20, 31, 27, 15, 29)
x < 22
[1]  TRUE  TRUE FALSE FALSE  TRUE FALSE

Nos devolverá un vector lógico, en función de si cada elemento cumple o no la condición pedida (de igual longitud que el vector preguntado)

Si tuviéramos un dato ausente (por error del aparato ese día), la condición evaluada también sería NA

y <- c(15, 20, NA, 31, 27, 7, 29, 10)
y < 22
[1]  TRUE  TRUE    NA FALSE FALSE  TRUE FALSE  TRUE

Comparar vectores

Las condiciones lógicas pueden ser combinadas de dos maneras:

  • Intersección: todas las condiciones concatenadas se deben cumplir (conjunción y con &) para devolver un TRUE
x < 30 & x > 15
[1] FALSE  TRUE FALSE  TRUE FALSE  TRUE
  • Unión: basta con que al menos una se cumpla (conjunción o con |)
x < 30 | x > 15
[1] TRUE TRUE TRUE TRUE TRUE TRUE

Con any() y all() podemos comprobar que todos los elementos cumplen

any(x < 30)
[1] TRUE
all(x < 30)
[1] FALSE

Acceder a elementos

Otra operación muy habitual es la de acceder a elementos. La forma más sencilla es usar el operador [i] (acceder al elemento i-ésimo)

edades <- c(20, 30, 33, NA, 61) 
edades[3] # accedemos a la edad de la tercera persona 
[1] 33

Dado que un número no es más que un vector de longitud uno, esta operación también la podemos aplicar usando un vector de índices a seleccionar

y <- c("hola", "qué", "tal", "estás", "?")
y[c(1:2, 4)] # primer, segundo y cuarto elemento
[1] "hola"  "qué"   "estás"

Consejo

Para acceder al último, sin preocuparnos de cuál es, podemos pasarle como índice la propia longitud x[length(x)]

Eliminar elementos

Otras veces no querremos seleccionar sino eliminar algunos elementos. Deberemos repetir la misma operación pero con el signo - delante: el operador [-i] no selecciona el elemento i-ésimo del vector sino que lo «des-selecciona»

y
[1] "hola"  "qué"   "tal"   "estás" "?"    
y[-2]
[1] "hola"  "tal"   "estás" "?"    

En muchas ocasiones los queremos seleccionar o eliminar en base a condiciones lógicas, en función de los valores, así que pasaremos como índice la propia condición (recuerda, x < 2 nos devuelve un vector lógico)

edades <- c(15, 21, 30, 17, 45)
nombres <- c("javi", "maría", "laura", "carla", "luis")
nombres[edades < 18] # nombres de los menores de edad
[1] "javi"  "carla"

Sumar vectores

También podemos hacer uso de operaciones estadísticas como por ejemplo sum() que, dado un vector, nos devuelve la suma de todos sus elementos.

x <- c(1, -2, 3, -1)
sum(x)
[1] 1

¿Qué sucede cuando falta un dato (ausente)?

x <- c(1, -2, 3, NA, -1)
sum(x)
[1] NA

Por defecto, si tenemos un dato ausente, la operación también será ausente. Para poder obviar ese dato, usamos un argumento opcional na.rm = TRUE

sum(x, na.rm = TRUE)
[1] 1

Sumar vectores

Como hemos comentado que los valores lógicos son guardados internamente como 0 y 1, podremos usarlos en operaciones aritméticas.

Por ejemplo, si queremos averiguar el número de elementos que cumplen una condición (por ejemplo, menores que 3), los que lo hagan tendrán asignado un 1 (TRUE) y los que no un 0 (FALSE) , por lo que basta con sumar dicho vector lógico para obtener el número de elementos que cumplen

x <- c(2, 4, 6)
sum(x < 3)
[1] 1

Suma acumulada

Otra operación habitual que puede sernos útil es la suma acumulada con cumsum() que, dado un vector, nos devuelve un vector a su vez con el primero, el primero más el segundo, el primero más el segundo más el tercero…y así sucesivamente.

x <- c(1, 5, 2, -1, 8)
cumsum(x)
[1]  1  6  8  7 15

¿Qué sucede cuando falta un dato (ausente)?

x <- c(1, -2, 3, NA, -1)
cumsum(x)
[1]  1 -1  2 NA NA

En el caso de la suma acumulada lo que sucede es que a partir de ese valor, todo lo acumulado posterior será ausente.

Diferencia

Otra operación habitual que puede sernos útil es la diferencia (con retardo) con diff() que, dado un vector, nos devuelve un vector con el segundo menos el primero, el tercero menos el segundo, el cuarto menos el tercero…y así sucesivamente.

x <- c(1, 8, 5, 3, 9, 0, -1, 5)
diff(x)
[1]  7 -3 -2  6 -9 -1  6

Con el argumento lag = podemos indicar el retardo de dicha diferencia (por ejemplo, lag = 3 implica que se resta el cuarto menos el primero, el quinto menos el segundo, etc)

x <- c(1, 8, 5, 3, 9, 0, -1, 5)
diff(x, lag = 3)
[1]  2  1 -5 -4 -4

Media

Otras operaciones habituales son la media, mediana, percentiles, etc.

  • Media: medida de centralidad que consiste en sumar todos los elementos y dividirlos entre la cantidad de elementos sumados. La más conocida pero la menos robusta: dado un conjunto, si se introducen valores atípicos o outliers (valores muy grandes o muy pequeños), la media se perturba con mucha facilidad.
x <- c(165, 170, 181, 191, 150, 155, 167, NA, 173, 177)
mean(x, na.rm = TRUE)
[1] 169.8889

Percentiles

Otras operaciones habituales son la media, mediana, percentiles, etc.

  • Mediana: medida de centralidad que consiste en ordenar los elementos y quedarse con el que ocupa la mitad.
x <- c(165, 170, 181, 191, 150, 155, 167, 173, 177)
median(x)
[1] 170
  • Percentiles: medidas de posición (nos dividen en partes iguales los datos).
quantile(x) # por defecto percentiles 0-25-50-75-100
  0%  25%  50%  75% 100% 
 150  165  170  177  191 
quantile(x, probs = c(0.1, 0.4, 0.9))
  10%   40%   90% 
154.0 167.6 183.0 

Ordenar vectores

Por último, una acción habitual es saber ordenar valores:

  • sort(): devuelve el vector ordenado. Por defecto de menor a mayor pero con decreasing = TRUE podemos cambiarlo
edades <- c(81, 7, 25, 41, 65, 20, 33, 23, 77)
sort(edades)
[1]  7 20 23 25 33 41 65 77 81
sort(edades, decreasing = TRUE)
[1] 81 77 65 41 33 25 23 20  7
  • order(): devuelve el vector de índices que tendríamos que usar para tener el vector ordenado
order(x)
[1] 5 6 1 7 2 8 9 3 4
x[order(x)]
[1] 150 155 165 167 170 173 177 181 191

💻 Tu turno

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Define el vector x como la concatenación de los 5 primeros números impares. Calcula la longitud del vector

Código
# Dos formas
x <- c(1, 3, 5, 7, 9)
x <- seq(1, 9, by = 2)

length(x)

📝 Accede al tercer elemento de x. Accede al último elemento (sin importar la longitud, un código que pueda ejecutarse siempre). Elimina el primer elemento.

Código
x[3]
x[length(x)]
x[-1]

📝 Obtén los elementos de x mayores que 4. Calcula el vector 1/x y guárdalo en una variable.

Código
x[x > 4]
z <- 1/x
z

📝 Crea un vector que represente los nombres de 5 personas, de los cuales uno es desconocido.

Código
nombres <- c("Javi", "Sandra", NA, "Laura", "Carlos")
nombres

📝 Encuentra del vector x de ejercicios anteriores los elementos mayores (estrictos) que 1 Y ADEMÁS menores (estrictos) que 7. Encuentra una forma de averiguar si todos los elementos son o no positivos.

Código
x[x > 1 & x < 7]
all(x > 0)

📝 Dado el vector x <- c(1, -5, 8, NA, 10, -3, 9), ¿por qué su media no devuelve un número sino lo que se muestra en el código inferior?

x <- c(1, -5, 8, NA, 10, -3, 9)
mean(x)
[1] NA

📝 Dado el vector x <- c(1, -5, 8, NA, 10, -3, 9), extrae los elementos que ocupan los lugares 1, 2, 5, 6.

Código
x <- c(1, -5, 8, NA, 10, -3, 9)
x[c(1, 2, 5, 6)]
x[-2]

📝 Dado el vector x del ejercicio anterior, ¿cuales tienen un dato ausente? Pista: las funciones is.algo() comprueban si el elemento es tipo algo (tabula)

Código
is.na(x)

📝 Define el vector x como la concatenación de los 4 primeros números pares. Calcula el número de elementos de x menores estrictamente que 5.

Código
x[x < 5] 
sum(x < 5)

📝 Calcula el vector 1/x y obtén la versión ordenada (de menor a mayor) de las dos formas posibles

Código
z <- 1/x
sort(z)
z[order(z)]
Código
min(x)
max(x)

📝 Encuentra del vector x los elementos mayores (estrictos) que 1 y menores (estrictos) que 6. Encuentra una forma de averiguar si todos los elementos son o no negativos.

Código
x[x > 1 & x < 7]
all(x > 0)

🐣 Caso práctico

En el paquete {datasets} (ya instalado por defecto) tenemos diversos conjuntos de datos y uno de ellos es airquality. Debajo te he extraído 3 variables de dicho dataset (fíjate que se hace con datos$variable)

library(datasets)
temperature <- airquality$Temp
month <- airquality$Month
day <- airquality$Day

Intenta responder a las preguntas planteadas en el workbook

  1. ¿Qué representan los datos? ¿Cómo averiguarlo?
Código
? airquality

Haciendo uso de ? ... podemos consultar en el panel de ayuda lo que significa el objeto.

🐣 Caso práctico

  1. ¿Cuántos registros tenemos de mayo? ¿Y de abril? Construye una nueva variable date con la fecha de cada registro (combinando año, mes y día)
Código
# Una forma para registros de mayo
sum(month == 5)
[1] 31
Código
# Otra forma
length(month[month == 5])
[1] 31
Código
# ídem en abril
sum(month == 4)
[1] 0
Código
# variable date
dates <- lubridate::as_date(glue("{1973}-{month}-{day}"))
  1. Crea una nueva variable temp_celsius con la temperatura en ºC
Código
# Temperatura en celsius
temp_celsius <- (temperature - 32) * (5/9)

🐣 Caso práctico

  1. ¿Cuál fue la media de temperatura del mes de agosto? Extrae los días en los que la temperatura superó los 30 grados y calcula la cantidad de días en los que lo hizo.
Código
# media en agosto
mean(temperature[month == 8], na.rm = TRUE)
[1] 83.96774
Código
mean(temp_celsius[month == 8], na.rm = TRUE)
[1] 28.87097
Código
# Extremos días > 30
dates[temp_celsius > 30]
 [1] "1973-06-08" "1973-06-09" "1973-06-10" "1973-06-11" "1973-06-12"
 [6] "1973-07-07" "1973-07-08" "1973-07-09" "1973-07-10" "1973-07-14"
[11] "1973-07-19" "1973-07-28" "1973-08-06" "1973-08-07" "1973-08-08"
[16] "1973-08-09" "1973-08-10" "1973-08-27" "1973-08-28" "1973-08-29"
[21] "1973-08-30" "1973-08-31" "1973-09-01" "1973-09-02" "1973-09-03"
[26] "1973-09-04" "1973-09-05"
Código
length(dates[temp_celsius > 30]) # n días
[1] 27
Código
sum(temp_celsius > 30) # n días (otra forma)
[1] 27
  • ordenar

  • microbenchmark

Clase 3: primeras bases de datos

Profundizando en variables de tipo texto. Primeras bases de datos

Profundizando en textos

💻 Tu turno (textos)

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 …

📝 …

📝 …

📝 …

📝

Primera base de datos

Cuando analizamos datos solemos tener varias variables de cada individuo: necesitamos una «tabla» que las recopile. La opción más inmediata son las matrices: concatenación de variables del mismo tipo e igual longitud.

Imagina que tenemos estaturas y pesos de 4 personas. ¿Cómo crear un dataset con las dos variables?

La opción más habitual es usando cbind(): concatenamos (bind) vectores en forma de columnas (c)

estaturas <- c(150, 160, 170, 180)
pesos <- c(63, 70, 85, 95)
datos_matriz <- cbind(estaturas, pesos)
datos_matriz
     estaturas pesos
[1,]       150    63
[2,]       160    70
[3,]       170    85
[4,]       180    95

Primer intento: matrices

También podemos construir la matriz por filas con la función rbind() (concatenar - bind - por filas - rows), aunque lo recomendable es tener cada variable en columna e individuo en fila como luego veremos.

rbind(estaturas, pesos) # Construimos la matriz por filas
          [,1] [,2] [,3] [,4]
estaturas  150  160  170  180
pesos       63   70   85   95
  • Podemos «visualizar» la matriz con View(matriz).
  • Podemos comprobar las dimensiones con dim(), nrow() y ncol(): las matrices son un tipo de datos tabulados (organizados en filas y columnas)
dim(datos_matriz)
[1] 4 2
nrow(datos_matriz)
[1] 4
ncol(datos_matriz)
[1] 2

Primer intento: matrices

También podemos «darle vuelta» (matriz transpuesta) con t().

t(datos_matriz)
          [,1] [,2] [,3] [,4]
estaturas  150  160  170  180
pesos       63   70   85   95

Dado que ahora tenemos dos dimensiones en nuestros datos, para acceder a elementos con [] deberemos proporcionar dos índices separados por comas: índice de la fila y de la columna

datos_matriz[2, 1] # segunda fila, primera columna
estaturas 
      160 
datos_matriz[1, 2] # primera fila, segunda columna 
pesos 
   63 

Primer intento: matrices

En algunas casos querremos obtener los datos totales de un individuo (una fila concreta pero todas las columnas) o los valores de toda una variable para todos los individuos (una columna concreta pero todas las filas). Para ello dejaremos sin rellenar uno de los índices

datos_matriz[2, ] # segundo individuo
estaturas     pesos 
      160        70 
datos_matriz[, 1] # primera variable
[1] 150 160 170 180

Mucho de lo aprendido con vectores podemos hacerlo con matrices, así podemos por ejemplo acceder a varias filas y/o columnas haciendo uso de las secuencias de enteros 1:n

datos_matriz[c(1, 3), 1] # primera variable para el primer y tercer individuo
[1] 150 170

Primer intento: matrices

También podemos definir una matriz a partir de un vector numérico, reorganizando los valores en forma de matriz (sabiendo que los elementos se van colocando por columnas).

z <- matrix(1:9, ncol = 3) 
z
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

Incluso podemos definir una matriz de valores constantes, por ejemplo de ceros (para luego rellenar)

matrix(0, nrow = 2, ncol = 3)
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0

Operaciones con matrices

Con las matrices sucede como con los vectores: cuando aplicamos una operación aritmética lo hacemos elemento a elemento

z/5
     [,1] [,2] [,3]
[1,]  0.2  0.8  1.4
[2,]  0.4  1.0  1.6
[3,]  0.6  1.2  1.8

Para realizar operaciones en un sentido matricial deberemos añadir %%, por ejemplo, para multiplicar matrices será %*%

z * t(z)
     [,1] [,2] [,3]
[1,]    1    8   21
[2,]    8   25   48
[3,]   21   48   81
z %*% t(z)
     [,1] [,2] [,3]
[1,]   66   78   90
[2,]   78   93  108
[3,]   90  108  126

Operaciones con matrices

También podemos realizar operaciones por columnas/filas sin recurrir a bucles con la función apply(), y le indicaremos como argumentos

  • la matriz
  • el sentido de la operación (MARGIN = 1 por filas, MARGIN = 2 por columnas)
  • la función a aplicar
  • argumentos extra que necesite la función

Por ejemplo, para aplicar una media a cada variable, será mean aplicada con MARGIN = 2 (misma función para cada columna)

# Media (mean) por columnas (MARGIN = 2)
apply(datos_matriz, MARGIN = 2, FUN = "mean")
estaturas     pesos 
   165.00     78.25 

💻 Tu turno (matrices)

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Modifica el código inferior para definir una matriz x de unos, de 3 filas y 7 columnas.

x <- matrix(0, nrow = 2, ncol = 3)
x
Código
x <- matrix(1, nrow = 3, ncol = 7)
x

📝 A la matriz anterior, suma un 1 a cada número de la matriz y divide el resultado entre 5. Tras ello calcula su transpuesta

Código
new_matrix <- (x + 1)/5
t(new_matrix)

📝 ¿Por qué el código inferior nos devuelve dicho mensaje de aviso?

matrix(1:15, nrow = 4)
Warning in matrix(1:15, nrow = 4): la longitud de los datos [15] no es un
submúltiplo o múltiplo del número de filas [4] en la matriz
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12    1

📝 Define la matriz x <- matrix(1:12, nrow = 4). Tras ello obtén los datos del primer individuo, los datos de la tercera variable, y el elemento (4, 1).

Código
x <- matrix(1:12, nrow = 4)
x[1, ] # primera fila
x[, 3] # tercera columna
x[4, 1] # elemento (4, 1)

📝 Define una matriz de 2 variables y 3 individuos tal que cada variable capture la estatura y la edad 3 personas, de manera que la edad de la segunda persona sea desconocida (ausente). Tras ello calcula la media de cada variable (¡nos debe de volver un número!)

Código
datos <- cbind("edad" = c(20, NA, 25), "estatura" = c(160, 165, 170))
apply(datos, MARGIN = 2, FUN = "mean", na.rm = TRUE) # media por columnas

📝 ¿Por qué devuelve error el código inferior? ¿Qué está mal?

matriz <- cbind("edad" = c(15, 20, 25), "nombres" = c("javi", "sandra", "carlos"))
matriz
     edad nombres 
[1,] "15" "javi"  
[2,] "20" "sandra"
[3,] "25" "carlos"
matriz + 1
Error in matriz + 1: argumento no-numérico para operador binario

Segundo intento: data.frame

Las matrices tienen el mismo problema que los vectores: si juntamos datos de distinto tipo, se perturba la integridad del dato ya que los convierte (fíjate en el código inferior: las edades y los TRUE/FALSE los ha convertido a texto)

edades <- c(14, 24, NA)
soltero <- c(TRUE, NA, FALSE)
nombres <- c("javi", "laura", "lucía")
matriz <- cbind(edades, soltero, nombres)
matriz
     edades soltero nombres
[1,] "14"   "TRUE"  "javi" 
[2,] "24"   NA      "laura"
[3,] NA     "FALSE" "lucía"

De hecho al no ser números ya no podemos realizar operaciones aritméticas

matriz + 1
Error in matriz + 1: argumento no-numérico para operador binario

Segundo intento: data.frame

Para poder trabajar con variables de distinto tipo tenemos en R lo que se conoce como data.frame: concatenación de variables de igual longitud pero que pueden ser de tipo distinto.

tabla <- data.frame(edades, soltero, nombres)
class(tabla)
[1] "data.frame"
tabla
  edades soltero nombres
1     14    TRUE    javi
2     24      NA   laura
3     NA   FALSE   lucía

Segundo intento: data.frame

Dado que un data.frame es ya un intento de «base de datos» las variables no son meros vectores matemáticos: tienen un significado y podemos (debemos) ponerles nombres que describan su significado

library(lubridate)
tabla <-
  data.frame("edad" = edades, "estado" = soltero, "nombre" = nombres,
             "f_nacimiento" = as_date(c("1989-09-10", "1992-04-01", "1980-11-27")))
tabla
  edad estado nombre f_nacimiento
1   14   TRUE   javi   1989-09-10
2   24     NA  laura   1992-04-01
3   NA  FALSE  lucía   1980-11-27

Segundo intento: data.frame

¡TENEMOS NUESTRO PRIMER CONJUNTO DE DATOS! (estrictamente no podemos hablar de base de datos pero de momento como lo si fuesen). Puedes visualizarlo escribiendo su nombre en consola o con View(tabla)

Acceso a variables

Si queremos acceder a sus elementos, al ser de nuevo datos tabulados, podemos acceder como en las matrices (no recomendable): de nuevo tenemos dos índices (filas y columnas, dejando libre la que no usemos)

tabla[2, ]  # segunda fila (todas sus variables)
  edad estado nombre f_nacimiento
2   24     NA  laura   1992-04-01
tabla[, 3]  # tercera columna (de todos los individuos)
[1] "javi"  "laura" "lucía"
tabla[2, 1]  # primera característica de la segunda persona
[1] 24

Pero también tiene las ventajas de una «base» de datos : podemos aceder a las variables por su nombre (lo recomendable ya que las variables pueden cambiar de posición y ahora sí tienen un significado), poniendo el nombre de la tabla seguido del símbolo $ (con el tabulador, nos aparecerá un menú de columnas a elegir)

Funciones de consulta

  • names(): nos muestra los nombres de las variables
names(tabla)
[1] "edad"         "estado"       "nombre"       "f_nacimiento"
  • dim(): nos muestra las dimensiones (también nrow() y ncol())
dim(tabla)
[1] 3 4
  • Podemos acceder a las variables por su nombre
tabla[c(1, 3), "nombre"]
[1] "javi"  "lucía"
tabla$nombre[c(1, 3)]
[1] "javi"  "lucía"

Añadir variable

Si tenemos uno ya creado y queremos añadir una columna es tan simple como usar la función data.frame() que ya hemos visto para concatenar la columna. Vamos añadir por ejemplo una nueva variable, el número de hermanos de cada individuo.

# Añadimos una nueva columna con nº de hermanos/as
hermanos <- c(0, 2, 3)
tabla <- data.frame(tabla, "n_hermanos" = hermanos)
tabla
  edad estado nombre f_nacimiento n_hermanos
1   14   TRUE   javi   1989-09-10          0
2   24     NA  laura   1992-04-01          2
3   NA  FALSE  lucía   1980-11-27          3

Intento final: tibble

Las tablas en formato data.frame tienen algunas limitaciones. La principal es que no permite la recursividad: imagina que definimos una base de datos con estaturas y pesos, y queremos una tercera variable con el IMC

data.frame("estatura" = c(1.7, 1.8, 1.6), "peso" = c(80, 75, 70),
           "IMC" = peso / (estatura^2))
Error in data.frame(estatura = c(1.7, 1.8, 1.6), peso = c(80, 75, 70), : objeto 'peso' no encontrado

En adelante usaremos el formato tibble (data.frame mejorado) del paquete {tibble}

library(tibble)
datos_tb <- 
  tibble("estatura" = c(1.7, 1.8, 1.6), "peso" = c(80, 75, 70), "IMC" = peso / (estatura^2))
class(datos_tb)
[1] "tbl_df"     "tbl"        "data.frame"
datos_tb
# A tibble: 3 × 3
  estatura  peso   IMC
     <dbl> <dbl> <dbl>
1      1.7    80  27.7
2      1.8    75  23.1
3      1.6    70  27.3

Intento final: tibble

datos_tb <-
  tibble("estatura" = c(1.7, 1.8, 1.6), "peso" = c(80, 75, 70), "IMC" = peso / (estatura^2))
datos_tb
# A tibble: 3 × 3
  estatura  peso   IMC
     <dbl> <dbl> <dbl>
1      1.7    80  27.7
2      1.8    75  23.1
3      1.6    70  27.3

Las tablas en formato tibble nos permitirá una gestión más ágil, eficiente y coherente de los datos, con 4 ventajas principales:

  • Metainformación: si te fijas en la cabecera, nos dice ya automáticamente el número de filas y columnas, y el tipo de cada variable
  • Recursividad: permite definir las variables secuencialmente (como hemos visto)

Intento final: tibble

  • Consistencia: si accedes a una columna que no existe avisa con un warning
datos_tb$invent
Warning: Unknown or uninitialised column: `invent`.
NULL
  • Por filas: crear por filas (copiar y pegar de una tabla) con tribble()
tribble(~colA, ~colB,
        "a",   1,
        "b",   2)
# A tibble: 2 × 2
  colA   colB
  <chr> <dbl>
1 a         1
2 b         2

Consejo

El paquete {datapasta} nos permite copiar y pegar tablas de páginas web y documentos sencillos

Recapitulando

  • Cada celda puede ser de un tipo diverso: números, texto, fechas, valores lógicos, etc
  • Un vector es una concatenación de celdas (las futuras columnas de nuestras tablas) –> En R por defecto las operaciones se hacen elemento a elemento
  • Una matriz nos permite concatenar variables del MISMO tipo y MISMA longitud –> datos tabulados
  • Un data.frame nos permite concatenar variables de DISTINTO tipo y MISMA longitud –> usaremos tibble como una opción mejorada de base de datos

💻 Tu turno (tb/df)

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Carga del paquete {datasets} el conjunto de datos airquality (variables de la calidad del aire de Nueva York desde mayo hasta septiembre de 1973). ¿Es el conjunto de datos airquality de tipo tibble? En caso negativo, conviértelo a tibble (busca en la documentación del paquete en https://tibble.tidyverse.org/index.html).

Código
library(tibble)
class(datasets::airquality)
airquality_tb <- as_tibble(datasets::airquality)

📝 Una vez convertido a tibble obtén el nombre de las variables y las dimensiones del conjunto de datos. ¿Cuántas variables hay? ¿Cuántos días se han medido?

Código
names(airquality_tb)
ncol(airquality_tb)
nrow(airquality_tb)

📝 Filtra solo los datos de la quinta observación

Código
airquality_tb[Month == 8, ]

📝 Filtra solo los datos del mes de agosto. ¿Cómo indicarle que queremos solo las filas que cumplan una condición concreta? (pista: en realidad todo son vectores “formateados”)

Código
airquality_tb[Month == 8, ]

📝 Selecciona aquellos datos que no sean ni de julio ni de agosto.

Código
airquality_tb[Month != 7 & Month != 8, ]
airquality_tb[!(Month %in% c(7, 8)), ]

📝 Modifica el siguiente código para quedarte solo con las variable de ozono y temperatura (sin importar qué posición ocupen)

airquality_tb[, 3]

📝 Selecciona los datos de temperatura y viento de agosto.

Código
airquality_tb[Month == 8, c("Temp", "Wind")]

📝 Traduce a castellano el nombre de las variables.

Código
names(airquality_tb) <- c("ozono", "rad_solar", "viento", "temp", "mes", "dia") 

🐣 Caso práctico

Del paquete Biostatistics usaremos el conunto de datos pinniped

Biostatistics::pinniped
  1. ¿Qué representan los datos? ¿Qué tipo de dato es? En caso de que no lo sea, convierte la base de datos a un tibble (renombra con pinniped_tb)
Código
? Biostatistics::pinniped
Código
class(Biostatistics::pinniped) # no es un tibble
[1] "data.frame"
Código
pinniped_tb <- as_tibble(Biostatistics::pinniped)
  1. ¿Cuántos registros hay? ¿Y variables? ¿De qué tipo es cada una?
Código
nrow(pinniped_tb)
[1] 33
Código
ncol(pinniped_tb)
[1] 6

🐣 Caso práctico

  1. Incorpora una variable extra llamada phoca que sea de tipo lógico y que nos diga si una especie es de la categoría Phoca o no.
Código
pinniped_tb$phoca <- pinniped_tb$Species == "Phoca"
  1. ¿A qué sexo le pesa más el cerebro: a las hembras o a los machos? ¿A quienes les pesa más el cuerpo: a los monógamos o a los polígamos?
Código
# ¿a quién le pesa más el cerebro?
mean(pinniped_tb$Male_brain_g, na.rm = TRUE) >
  mean(pinniped_tb$Female_brain_g, na.rm = TRUE)
[1] TRUE
Código
# ¿a quién le pesa más el cerebro?
mean(c(pinniped_tb$Male_mass_Kg[pinniped_tb$Mate_type == "mono"],
       pinniped_tb$Female_mass_Kg[pinniped_tb$Mate_type == "mono"])) >
  mean(c(pinniped_tb$Male_mass_Kg[pinniped_tb$Mate_type == "poly"],
         pinniped_tb$Female_mass_Kg[pinniped_tb$Mate_type == "poly"]))
[1] FALSE

🐣 Caso práctico

  1. Incopora una nueva variable que represente la diferencia entre el peso del cerebro entre machos y hembras (machos - hembras) para cada especie.
Código
pinniped_tb$dif_m_f <- pinniped_tb$Male_brain_g - pinniped_tb$Female_brain_g
pinniped_tb
# A tibble: 33 × 8
   Species     Male_brain_g Female_brain_g Male_mass_Kg Female_mass_Kg Mate_type
   <chr>              <dbl>          <dbl>        <dbl>          <dbl> <chr>    
 1 Monachus s…         370             NA          173            272. mono     
 2 Monachus m…         480            480          260            275  mono     
 3 Mirounga a…         700            640         2275            488  poly     
 4 Mirounga l…        1431.           899.        3510            566. poly     
 5 Leptonycho…         535            638.         450            447  poly     
 6 Ommatophoc…         425            530          154.           164  mono     
 7 Lobodon ca…         578.           539.         220.           224  mono     
 8 Hydrurga l…         765            660          324            367  mono     
 9 Cystophora…         480            430          343.           222. mono     
10 Erignathus…          NA            460          312.           326  mono     
# ℹ 23 more rows
# ℹ 2 more variables: phoca <lgl>, dif_m_f <dbl>